home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-10-18 | 18.9 KB | 602 lines | [TEXT/MMCC] |
-
- #include "DBElementToken.h"
- #include "DBElementTokenIterator.h"
-
- #include "Application.h"
- #include "DBElement.h"
- #include "DBProperty.h"
- #include "Transaction.h"
- #include "ScriptableDBDocument.h"
- #include "AbstractProperty.h"
-
- #include <AERegistry.h>
- #include <ASRegistry.h>
-
- #include "Exceptions.h"
-
- TDescriptor GetDataAsDescriptor(TTransaction* t, AConst<TDBProperty> propertyRecord);
-
-
- //--------------------------------------------------------------------------------
- // GetDataAsDescriptor
- //--------------------------------------------------------------------------------
- TDescriptor GetDataAsDescriptor(TTransaction* t, AConst<TDBProperty> propertyRecord)
- {
- TDescriptor result;
-
- if(propertyRecord.Exists())
- {
- //
- // Bunches of code just to copy the property data into a handle
- //
- long propertyType = propertyRecord->GetDataType(t);
- long propertyLength = propertyRecord->GetDataLength(t);
-
- Handle propertyDataStorage = NewHandle(propertyLength);
- FailErr(MemError());
- HLock(propertyDataStorage);
- propertyRecord->GetTypedData(t, TUpdataDataReference(propertyType, *propertyDataStorage, propertyLength, propertyLength));
- HUnlock(propertyDataStorage);
-
- //
- // Once we have the property type and all of the data in
- // a handle, we can package up a TDescriptor
- //
- result.AdoptHandle(propertyType, propertyDataStorage);
- }
-
- return result;
- } // GetDataAsDescriptor
-
- #define clDBElementToken 33
-
- #pragma segment ObjectResident
- ImplementSmallClassData(TDBElementToken, clDBElementToken);
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::TDBElementToken
- //--------------------------------------------------------------------------------
- TDBElementToken::TDBElementToken(AConst<TDBElement> record) : fRecord(record)
- {
- record->AddReference();
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::~TDBElementToken
- //--------------------------------------------------------------------------------
- TDBElementToken::~TDBElementToken()
- {
- fRecord->RemoveReference();
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::CloneOwnedObjects
- //--------------------------------------------------------------------------------
- void TDBElementToken::CloneOwnedObjects()
- {
- //
- // fRecord has been cloned, so we need to add one more reference to it
- //
- fRecord->AddReference();
- } // TDBElementToken::CloneOwnedObjects
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::ObjectClass
- //--------------------------------------------------------------------------------
- DescType TDBElementToken::ObjectClass(TTransaction* t, Boolean /*recordedClass*/)
- {
- DescType objectClass = cObject;
- long unusedLength = 0;
- long unusedType = 0;
- AConst<TDBProperty> propertyRecord = fRecord->GetPropertyRecord(t, pClass);
-
- if(propertyRecord.Exists())
- propertyRecord->GetTypedData(t, TUpdataDataReference(typeType, (char*)&objectClass, sizeof(DescType), sizeof(DescType)));
-
- return objectClass;
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::DerivedFromOSLClass
- //--------------------------------------------------------------------------------
- Boolean TDBElementToken::DerivedFromOSLClass(TTransaction* t, DescType objectClass)
- {
- return ((objectClass == this->ObjectClass(t)) || (Inherited::DerivedFromOSLClass(t, objectClass)));
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::ParentObject
- //--------------------------------------------------------------------------------
- TAbstractScriptableObject* TDBElementToken::ParentObject(TTransaction* t)
- {
- TAbstractScriptableObject* parent = nil;
- AConst<TDBRecord> parentElement = fRecord->TreeOwner(t);
-
- //
- // If this node has a parent, then it is not the metaroot
- //
- if(parentElement.Exists())
- {
- parent = new TDBElementToken(parentElement->DBElementCursor());
- }
- //
- // The parent of the metaroot is the scriptable db document
- // that contains this database document.
- //
- else
- {
- TDatabaseDocument* doc = fRecord->DBDocument();
- parent = gApplication->FindDocument(doc->ObjectsKeySpace());
- }
-
- return parent;
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::ElementIterator
- //--------------------------------------------------------------------------------
- TAbstractObjectIterator* TDBElementToken::ElementIterator(TTransaction* t)
- {
- // AConst<TDBRecord> elements = fRecord->Elements()->DBRecordCursor();
- AConst<TDBElement> elements = fRecord->Elements(t);
-
- TAbstractObjectIterator* iter = nil;
-
- if(elements.Exists())
- {
- iter = new TDBElementTokenIterator(t, elements->DBRecordCursor());
- }
-
- return iter;
- }
-
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::AccessByProperty
- //--------------------------------------------------------------------------------
- TAbstractScriptableObject* TDBElementToken::AccessByProperty(TTransaction* t, DescType propertyIdentifier)
- {
- TAbstractScriptableObject* result = nil;
-
- //
- // If we can generate a description for this property,
- // then call Inherited:: to make the property token
- //
- if(this->DescriptionOfProperty(t, propertyIdentifier) != nil)
- {
- result = Inherited::AccessByProperty(t, propertyIdentifier);
- }
- else
- {
- //
- // Problem: For this database, there should be some way
- // to create a property that does not exist yet under some
- // situations (maybe some databases will allow any property
- // to be added to any element, but most databases will
- // probably restrict the properties that each element can
- // have).
- //
- // We also need to specify that some properties are read
- // only (maybe?)
- //
- #if 0
- AConst<TDBProperty> propertyRecord = fRecord->GetPropertyRecord(propertyIdentifier);
- if(propertyRecord.Exists())
- #endif
- {
- //
- // We need some way to determine what the default type
- // and best type for any given property should be.
- //
- result = new TGenericProperty;
- ((TGenericProperty*)result)->IGenericProperty(this, TPropertyDataDescription(propertyIdentifier, 0, typeWildCard, typeWildCard));
- }
- }
-
- return result;
- }
-
-
- //================================================================================
- // Class TDescriptorComparisonObject
- //================================================================================
- class TDescriptorComparisonObject : public TAbstractDBComparisonObject
- {
- private:
- const TDescriptor fSearchKey;
-
- public:
- TDescriptorComparisonObject(TDescriptor& searchKey) : fSearchKey(searchKey) {};
-
- virtual CompareEnumeration TestObject(TTransaction*, AConst<TDBRecord>);
- };
-
- //--------------------------------------------------------------------------------
- // TDescriptorComparisonObject::TestObject
- //--------------------------------------------------------------------------------
- CompareEnumeration TDescriptorComparisonObject::TestObject(TTransaction* t, AConst<TDBRecord> testObject)
- {
- //
- // This is not a very fast way to compare, but it will do for now.
- //
- TDescriptor testName = GetDataAsDescriptor(t, testObject->DBElementCursor()->GetPropertyRecord(t, pName));
-
- //
- // This AppleEvent API that removes information from the result is annoying,
- // because it forces us to compare twice (ick).
- //
- // kAEGreaterThan
- // kAELessThan
- //
- Boolean isLess = fSearchKey.Compare(kAELessThan, testName);
- Boolean isGreater = fSearchKey.Compare(kAEGreaterThan, testName);
-
- //
- // kSecondObjectComesBefore = -1,
- // kObjectKeysEqual = 0,
- // kSecondObjectComesAfter = 1
- //
- return (isGreater ? kSecondObjectComesAfter : (isLess ? kSecondObjectComesBefore : kObjectKeysEqual));
- } // TDescriptorComparisonObject::TestObject
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::AccessByUniqueID
- //--------------------------------------------------------------------------------
- TAbstractScriptableObject* TDBElementToken::AccessByUniqueID(TTransaction* t, DescType desiredClass, TDescriptor uniqueID)
- {
- TAbstractScriptableObject* result = nil;
- long theRecordIndex = uniqueID.GetLong();
-
- //
- // Get the specified record from the database. The record
- // _must_ be a database element (not a property); if this is
- // a token for the metaroot, then allow any record in any tree
- // to be returned. Otherwise, require that the record we found
- // be a child of this record.
- //
- AConst<TDBElement> theRecord = fRecord->DBDocument()->GetRecordCursor(theRecordIndex)->DBElementCursor();
- if(theRecord.Exists())
- {
- AConst<TDBRecord> theRecordOwner = theRecord->TreeOwner(t);
- if(this->IsMetaRoot() || (theRecordOwner->RecordIndex() == fRecord->RecordIndex()))
- {
- result = new TDBElementToken(theRecord);
- if(result->DerivedFromOSLClass(t, desiredClass) == false)
- {
- result->DisposeDesignator();
- result = nil;
- }
- }
- }
-
- //
- // If we could not find an appropriate record with the given ID,
- // then call Inherited.
- //
- if(result == nil)
- result = Inherited::AccessByUniqueID(t, desiredClass, uniqueID);
-
- return result;
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::BestType
- //--------------------------------------------------------------------------------
- DescType TDBElementToken::BestType(TTransaction* t, DescType propertyName)
- {
- AConst<TDBProperty> propertyRecord = fRecord->GetPropertyRecord(t, propertyName);
- if(propertyRecord.Exists())
- {
- return propertyRecord->GetDataType(t);
- }
- else
- return typeNull;
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::DefaultType
- //--------------------------------------------------------------------------------
- DescType TDBElementToken::DefaultType(TTransaction* t, DescType propertyName)
- {
- AConst<TDBProperty> propertyRecord = fRecord->GetPropertyRecord(t, propertyName);
- if(propertyRecord.Exists())
- {
- return propertyRecord->GetDataType(t);
- }
- else
- return typeNull;
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::CanReturnDataOfType
- //--------------------------------------------------------------------------------
- Boolean TDBElementToken::CanReturnDataOfType(TTransaction*, DescType /*propertyName*/, DescType /*desiredType*/)
- {
- return true;
- }
-
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::GetProperty
- //--------------------------------------------------------------------------------
- TDescriptor TDBElementToken::GetProperty(TTransaction* t, DescType propertyName, DescType desiredType, unsigned long additionalInfo /*= 0*/)
- {
- TDescriptor result;
-
- switch(propertyName)
- {
- case pID:
- {
- result.MakeLong(fRecord->RecordIndex());
- break;
- }
-
- case pIndex:
- {
- if(this->IsMetaRoot())
- FailErr(errAENoSuchObject);
- else
- {
- long index = 0;
- AConst<TDBRecord> treeTop = fRecord->TopOfTree(t);
- for(TAbstractRecordIterator iter(t, treeTop); iter.More(); iter.Next())
- {
- ++index;
- if(iter.Current()->RecordIndex() == fRecord->RecordIndex())
- break;
- }
- result.MakeLong(index);
- }
- break;
- }
-
- default:
- {
- AConst<TDBProperty> propertyRecord = fRecord->GetPropertyRecord(t, propertyName);
- if(propertyRecord.Exists())
- {
- result = GetDataAsDescriptor(t, propertyRecord);
- }
- else
- result = Inherited::GetProperty(t, propertyName, desiredType, additionalInfo);
-
- break;
- }
- }
-
- return result;
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::CompareProperty
- //--------------------------------------------------------------------------------
- Boolean TDBElementToken::CompareProperty(TTransaction* t, DescType propertyIdentifier, DescType comparisonOperator, TDescriptor compareWith)
- {
- Boolean compareResult = false;
- Boolean didCompare = false;
-
- AConst<TDBProperty> propertyRecord = fRecord->GetPropertyRecord(t, propertyIdentifier);
- if(propertyRecord.Exists())
- {
- short oldState = compareWith.Lock();
-
- switch(comparisonOperator)
- {
- case kAEEquals:
- case kASNotEqual:
- case kAEGreaterThan:
- case kAEGreaterThanEquals:
- case kAELessThan:
- case kASLessThanOrEqual:
- {
- compareResult = InterpretCompareResult(comparisonOperator, propertyRecord->Compare(t, compareWith), 0 );
- didCompare = true;
- break;
- }
-
- case kAEContains:
- {
- compareResult = propertyRecord->Contains(t, compareWith);
- didCompare = true;
- break;
- }
-
- //
- // We don't export enough data to do begins with or
- // ends with, so we'll just call Inherited and allow
- // the comparison to be done the slow way.
- //
- case kAEBeginsWith:
- case kAEEndsWith:
- default:
- {
- didCompare = false;
- break;
- }
- }
-
- compareWith.Unlock(oldState);
- }
- else
- didCompare = false;
-
- //
- // If we couldn't do the compare, then call Inherited
- //
- if(didCompare == false)
- compareResult = Inherited::CompareProperty(t, propertyIdentifier, comparisonOperator, compareWith);
-
- return compareResult;
- } // TDBElementToken::CompareProperty
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::SetProperty
- //--------------------------------------------------------------------------------
- void TDBElementToken::SetProperty(TTransaction* transaction, DescType propertyName, TDescriptor& data, unsigned long /*additionalInfo = 0*/)
- {
- switch(propertyName)
- {
- case pIndex:
- case pID:
- {
- FailErr(errAENotModifiable);
- break;
- }
-
- default:
- {
- AnUpdate<TDBElement> updateElement = transaction->GetDBElementUpdatePointer(fRecord);
-
- HLock(data.DataHandle());
- char* dataPtr = *data.DataHandle();
- long dataLength = GetHandleSize(data.DataHandle());
- long dataType = data.DescriptorType();
-
- updateElement->AddTypedProperty(transaction, propertyName, TConstDataReference(dataType, dataPtr, dataLength));
- HUnlock(data.DataHandle());
-
- //
- // Make sure that the tree is still happy
- //
- fRecord->Verify(transaction, true);
- break;
- }
- }
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::BuildObjectSpecifier
- //--------------------------------------------------------------------------------
- TDescriptor TDBElementToken::BuildObjectSpecifier(TTransaction* t)
- {
- //
- // If this record is the metaroot, don't build
- // an object specifier for it; just make one
- // for the parent object
- //
- if(this->IsMetaRoot())
- return this->BuildSpecifierForParent(t);
- else
- return Inherited::BuildObjectSpecifier(t);
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::MakeKeyDataForSelf
- //--------------------------------------------------------------------------------
- void TDBElementToken::MakeKeyDataForSelf(TTransaction* t, DescType& keyForm, TDescriptor& keyData)
- {
- //
- // If we have a name property and this record is in a tree,
- // then describe this element as "element xxx" of <parent specifier>
- //
- AConst<TDBProperty> nameProperty = fRecord->GetPropertyRecord(t, pName);
- if(nameProperty.Exists() && fRecord->RecordIsInATree(t))
- {
- Inherited::MakeKeyDataForSelf(t, keyForm, keyData);
- }
- //
- // If there is no name property, OR if we have no parent, then describe
- // this element by unique ID.
- //
- else
- {
- keyForm = formUniqueID;
- keyData.MakeLong(fRecord->RecordIndex());
- }
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::BuildSpecifierForParent
- //--------------------------------------------------------------------------------
- TDescriptor TDBElementToken::BuildSpecifierForParent(TTransaction* t)
- {
- return Inherited::BuildSpecifierForParent(t);
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::AECommand
- //--------------------------------------------------------------------------------
- TDescriptor TDBElementToken::AECommand(TTransaction* t, TAEvent ae, TAEvent reply, long aeCommandID, TAbstractScriptableObject* auxObjects, long auxInfo)
- {
- TDescriptor result;
-
- switch(aeCommandID)
- {
- case kAEDelete:
- {
- AnUpdate<TDBElement> updateElement = t->GetDBElementUpdatePointer(fRecord);
- updateElement->FreeThisRecord(t);
-
- break;
- }
-
- default:
- {
- result = Inherited::AECommand(t, ae, reply, aeCommandID, auxObjects, auxInfo);
- break;
- }
- }
-
- return result;
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::CreateNewElement
- //--------------------------------------------------------------------------------
- TAbstractScriptableObject* TDBElementToken::CreateNewElement(TTransaction* transaction, TAEvent /*ae*/, TAEvent /*reply*/, DescType newObjectClass, TDescriptor /*initialData*/, TDescriptor /*initialProperties*/, Boolean& /*usedInitialData*/, Boolean& /*usedInitialProperties*/)
- {
- AnUpdate<TDBElement> updateElement = transaction->GetDBElementUpdatePointer(fRecord);
-
- AnUpdate<TDBElement> newElement = fRecord->DBDocument()->NewDBElement(transaction);
- newElement->AddTypedProperty(transaction, pClass, TConstDataReference(typeType, (Ptr)&newObjectClass, sizeof(DescType)));
- updateElement->AddElement(transaction, newElement);
-
- //
- // Make sure that the tree is still happy
- //
- fRecord->Verify(transaction, true);
-
- return new TDBElementToken(newElement);
- }
-
- //----------------------------------------------------------------------------------------
- // TDBElementToken::ObjectsAreTheSame:
- //----------------------------------------------------------------------------------------
- Boolean TDBElementToken::ObjectsAreTheSame(TTransaction*, TAbstractScriptableObject* objectToTest)
- {
- Boolean areTheSame = false;
-
- if(objectToTest->DerivedFrom(clDBElementToken))
- {
- areTheSame = ((this->RecordIndex() == ((TDBElementToken*)objectToTest)->RecordIndex()) &&
- (this->DocumentIdentifier() == ((TDBElementToken*)objectToTest)->DocumentIdentifier()));
- }
-
- return areTheSame;
- } // TDBElementToken::ObjectsAreTheSame
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::IsMetaRoot
- //--------------------------------------------------------------------------------
- Boolean TDBElementToken::IsMetaRoot()
- {
- return fRecord->RecordIndex() == fRecord->DBDocument()->MetaRootIndex();
- } // TDBElementToken::IsMetaRoot
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::RecordIndex
- //--------------------------------------------------------------------------------
- long TDBElementToken::RecordIndex()
- {
- return fRecord->RecordIndex();
- } // TDBElementToken::RecordIndex
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::DocumentIdentifier
- //--------------------------------------------------------------------------------
- Int64 TDBElementToken::DocumentIdentifier()
- {
- return fRecord->DBDocument()->ObjectsKeySpace();
- } // TDBElementToken::DocumentIdentifier
-
-